﻿@using Masuit.Tools.Hardware
@using Masuit.Tools.Win32
@using System.Net.Sockets
@using Masuit.MyBlogs.Core.Common
@using Masuit.Tools
@using System.IO
@using Masuit.Tools.Logging
@inject IJSRuntime JS;

<h3 class="text-center">
    服务器系统信息概览
</h3>
<table class="table table-inner table-vmiddle table-bordered">
    <tbody>
        <tr>
            <td>网站开机时长</td>
            <th>@runningTime</th>
            <td>服务器开机时长</td>
            <th>@bootTime</th>
            <td>操作系统</td>
            <th>@Environment.OSVersion.VersionString</th>
        </tr>
        <tr>
            <td>CPU型号</td>
            <th>@cpu.Type</th>
            <td>CPU基础频率</td>
            <th>@cpu.CurrentClockSpeed MHz</th>
            <td>CPU睿频</td>
            <th>@cpu.MaxClockSpeed MHz</th>
        </tr>
        <tr>
            <td>CPU个数</td>
            <th>@SystemInfo.GetCpuInfo().Count 插槽</th>
            <td>CPU核心数</td>
            <th>@cpu.NumberOfCores 核心</th>
            <td>CPU线程数</td>
            <th>@cpu.NumberOfLogicalProcessors 线程</th>
        </tr>
        <tr>
            <td>物理总内存</td>
            <th>@((memory.PhysicalMemory / 1048576).ToString("N2")) MB(@((memory.PhysicalMemory / 1073741824).ToString("N2")) GB)</th>
            <td>物理内存已使用</td>
            <th>@((memory.PhysicalMemory * memory.MemoryUsage / 104857600).ToString("N2")) MB(@((memory.PhysicalMemory * memory.MemoryUsage / 107374182400).ToString("N2")) GB)</th>
            <td>物理内存剩余</td>
            <th>@((memory.PhysicalMemory * (100 - memory.MemoryUsage) / 104857600).ToString("N2")) MB(@((memory.PhysicalMemory * (100 - memory.MemoryUsage) / 107374182400).ToString("N2")) GB)</th>
        </tr>
        <tr>
            <td>虚拟内存总数</td>
            <th>@((memory.TotalPageFile / 1048576).ToString("N2")) MB</th>
            <td>虚拟内存已使用</td>
            <th>@(((memory.TotalPageFile - memory.AvailablePageFile) / 1048576).ToString("N2")) MB</th>
            <td>虚拟内存可用</td>
            <th>@((memory.AvailablePageFile / 1048576).ToString("N2")) MB</th>
        </tr>
        <tr>
            <td>磁盘总空间</td>
            <th>@_driveInfos.Select(kv => kv.Name + " " + (kv.TotalSize * 1.0 / 1073741824).ToDecimal(2) + "GB").Join(" | ")</th>
            <td>磁盘剩余空间</td>
            <th>@_driveInfos.Select(kv => kv.Name + " " + (kv.TotalFreeSpace * 1.0 / 1073741824).ToDecimal(2) + "GB").Join(" | ")</th>
            <td>磁盘可用率</td>
            <th>@_driveInfos.Select(kv => kv.Name + " " + (kv.AvailableFreeSpace * 1m / kv.TotalSize).ToString("P")).Join(" | ")</th>
        </tr>
        <tr>
            <td>MAC地址</td>
            <th colspan="5">@macs.Join(" , ")</th>
        </tr>
        <tr>
            <td>IP地址</td>
            <th colspan="5">@ips.Join(" , ")</th>
        </tr>
    </tbody>
</table>

<h3 class="text-center">
    硬件占用百分位统计
</h3>
<table class="table table-inner table-vmiddle table-bordered">
    <thead>
        <tr>
            <th></th>
            <th>第 50 个百分位</th>
            <th>第 75 个百分位</th>
            <th>第 90 个百分位</th>
            <th>第 99 个百分位</th>
            <th>第 99.9 个百分位</th>
            <th>均值</th>
            <th>标准差</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var (key, value) in GetCounterPercent())
        {
            <tr>
                <th>@key</th>
                <td>@value.p50</td>
                <td>@value.p75</td>
                <td>@value.p90</td>
                <td>@value.p99</td>
                <td>@value.p999</td>
                <td>@value.average</td>
                <td>@value.stdev</td>
            </tr>
        }

    </tbody>
</table>
<button class="btn btn-success" @onclick="ClearMemory">整理内存</button>
<div>
    <div class="page-header">
        <h3 class="text-center">性能实时监控</h3>
    </div>
    <div class="row">
        <div id="container" class="col-md-3" style="height: 400px;"></div>
        <div id="container-cpu" class="col-md-5" style="height: 400px;"></div>
        <div id="container-io" class="col-md-4" style="height: 400px;"></div>
    </div>
</div>

@code {
    private string bootTime;
    private string runningTime;
    private readonly CpuInfo cpu = SystemInfo.GetCpuInfo()[0];
    private readonly RamInfo memory = SystemInfo.GetRamInfo();
    private readonly IList<string> macs = SystemInfo.GetMacAddress();
    private readonly IList<string> ips = SystemInfo.GetLocalIPs().OrderBy(u => u.Address.AddressFamily != AddressFamily.InterNetwork).Select(a => a.Address.ToString()).ToList();
    private readonly DriveInfo[] _driveInfos = DriveInfo.GetDrives().Where(d => d.IsReady).ToArray();

    protected override void OnInitialized()
    {
        var boot = DateTime.Now - SystemInfo.BootTime();
        var span = DateTime.Now - PerfCounter.StartTime;
        runningTime = $"{span.Days}天{span.Hours}小时{span.Minutes}分钟";
        bootTime = $"{boot.Days}天{boot.Hours}小时{boot.Minutes}分钟";
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await JS.InvokeVoidAsync("showLine");
    }

    [JSInvokable]
    public static PerformanceCounter GetCurrentPerformanceCounter()
    {
        try {
            return PerfCounter.GetCurrentPerformanceCounter();
        }
        catch (Exception e) {
            LogManager.Error(e);
            return new PerformanceCounter();
        }
    }

    public void ClearMemory()
    {
        Windows.ClearMemorySilent();
        JS.InvokeVoidAsync("showSuccess");
    }

    public Dictionary<string, dynamic> GetCounterPercent()
    {
        var counters = PerfCounter.List;
        var count = counters.Count;
        return new()
        {
            ["CPU使用率(%)"] = new
            {
                p50 = counters.OrderByDescending(c => c.CpuLoad).Take(count / 2).MinOrDefault(c => c.CpuLoad).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.CpuLoad).Take(count / 4).MinOrDefault(c => c.CpuLoad).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.CpuLoad).Take(count / 10).MinOrDefault(c => c.CpuLoad).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.CpuLoad).Take(count / 100).MinOrDefault(c => c.CpuLoad).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.CpuLoad).Take(count / 1000).MinOrDefault(c => c.CpuLoad).ToString("N2"),
                average = counters.Average(c => c.CpuLoad).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.CpuLoad).ToString("N2"),
            },
            ["内存使用率(%)"] = new
            {
                p50 = counters.OrderByDescending(c => c.MemoryUsage).Take(count / 2).MinOrDefault(c => c.MemoryUsage).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.MemoryUsage).Take(count / 4).MinOrDefault(c => c.MemoryUsage).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.MemoryUsage).Take(count / 10).MinOrDefault(c => c.MemoryUsage).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.MemoryUsage).Take(count / 100).MinOrDefault(c => c.MemoryUsage).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.MemoryUsage).Take(count / 1000).MinOrDefault(c => c.MemoryUsage).ToString("N2"),
                average = counters.Average(c => c.MemoryUsage).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.MemoryUsage).ToString("N2"),
            },
            ["磁盘读(KBps)"] = new
            {
                p50 = counters.OrderByDescending(c => c.DiskRead).Take(count / 2).MinOrDefault(c => c.DiskRead).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.DiskRead).Take(count / 4).MinOrDefault(c => c.DiskRead).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.DiskRead).Take(count / 10).MinOrDefault(c => c.DiskRead).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.DiskRead).Take(count / 100).MinOrDefault(c => c.DiskRead).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.DiskRead).Take(count / 1000).MinOrDefault(c => c.DiskRead).ToString("N2"),
                average = counters.Average(c => c.DiskRead).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.DiskRead).ToString("N2"),
            },
            ["磁盘写(KBps)"] = new
            {
                p50 = counters.OrderByDescending(c => c.DiskWrite).Take(count / 2).MinOrDefault(c => c.DiskWrite).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.DiskWrite).Take(count / 4).MinOrDefault(c => c.DiskWrite).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.DiskWrite).Take(count / 10).MinOrDefault(c => c.DiskWrite).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.DiskWrite).Take(count / 100).MinOrDefault(c => c.DiskWrite).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.DiskWrite).Take(count / 1000).MinOrDefault(c => c.DiskWrite).ToString("N2"),
                average = counters.Average(c => c.DiskWrite).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.DiskWrite).ToString("N2")
            },
            ["网络下载(KBps)"] = new
            {
                p50 = counters.OrderByDescending(c => c.Download).Take(count / 2).MinOrDefault(c => c.Download).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.Download).Take(count / 4).MinOrDefault(c => c.Download).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.Download).Take(count / 10).MinOrDefault(c => c.Download).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.Download).Take(count / 100).MinOrDefault(c => c.Download).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.Download).Take(count / 1000).MinOrDefault(c => c.Download).ToString("N2"),
                average = counters.Average(c => c.Download).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.Download).ToString("N2")
            },
            ["网络上行(KBps)"] = new
            {
                p50 = counters.OrderByDescending(c => c.Upload).Take(count / 2).MinOrDefault(c => c.Upload).ToString("N2"),
                p75 = counters.OrderByDescending(c => c.Upload).Take(count / 4).MinOrDefault(c => c.Upload).ToString("N2"),
                p90 = counters.OrderByDescending(c => c.Upload).Take(count / 10).MinOrDefault(c => c.Upload).ToString("N2"),
                p99 = counters.OrderByDescending(c => c.Upload).Take(count / 100).MinOrDefault(c => c.Upload).ToString("N2"),
                p999 = counters.OrderByDescending(c => c.Upload).Take(count / 1000).MinOrDefault(c => c.Upload).ToString("N2"),
                average = counters.Average(c => c.Upload).ToString("N2"),
                stdev = counters.StandardDeviation(c => c.Upload).ToString("N2")
            }
        };
    }
}
